﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Security;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

namespace Pg.BioMedics.SDR.Web.Security
{
    /// <summary>
    /// Provides user initializationd deinitialization during 
    /// context processing for the user
    /// </summary>
    public class ImpersonationModule : IHttpModule
    {
        #region Constants

        private const string ImpersonationContextKey = "ImpresonationContext";

        #endregion

        #region Credentials

        private static Dictionary<string, byte[]> credentialsCache = new Dictionary<string, byte[]>();

        #endregion

        #region Static methods
        
        /// <summary>
        /// Saves credentials in credentials cache. All credentials in cache are encrypted using DAPI
        /// aith IIS ASP .NET WP indentity session key.
        /// </summary>
        /// <param name="userName">User name</param>
        /// <param name="password">User password</param>
        internal static void StoreCredentials(string userName, string password)
        {
            if (credentialsCache.ContainsKey(userName))
                credentialsCache.Remove(userName);

            byte[] protectedPasswordBytes = ProtectedData.Protect(Encoding.Default.GetBytes(password),
                                                                  new byte[0], DataProtectionScope.CurrentUser);
            credentialsCache.Add(userName, protectedPasswordBytes);
        }

        #endregion        

        #region Event handlers 

        private void context_PostAuthenticateRequest(object sender, EventArgs e)
        {
            HttpContext context = HttpContext.Current;
            if (context.User.Identity.IsAuthenticated)
            {

                if (credentialsCache.ContainsKey(context.User.Identity.Name))
                {
                    string identityName = context.User.Identity.Name;
                    string domain = WindowsIdentityHelper.GetDomainName(identityName);
                    string userName = WindowsIdentityHelper.GetUserName(identityName);

                    string password = Encoding.Default.GetString(ProtectedData.Unprotect(credentialsCache[context.User.Identity.Name],
                                                                                         new byte[0], DataProtectionScope.CurrentUser));
                    WindowsImpersonationContext impersonationContext = WindowsIdentityHelper.ImpersonateValidUser(userName, domain, password);

                    password = null;
                    GC.Collect();
                    GC.WaitForPendingFinalizers();

                    context.Items.Add(ImpersonationContextKey, impersonationContext);
                }
            }
        }

        private void context_EndRequest(object sender, EventArgs e)
        {
            HttpContext context = HttpContext.Current;
            if (context.Items.Contains(ImpersonationContextKey))
            {
                WindowsImpersonationContext impresonationContext = context.Items[ImpersonationContextKey] as WindowsImpersonationContext;
                WindowsIdentityHelper.UndoImpersonation(impresonationContext);
            }
        }

        #endregion

        #region Support methods

        #endregion

        #region IHttpModule Members

        public void Dispose()
        {
  
        }

        public void Init(HttpApplication context)
        {
            if (Membership.Provider is WindowsMembershipProvider)
            {                
                context.PostAuthenticateRequest += new EventHandler(context_PostAuthenticateRequest);
                context.EndRequest += new EventHandler(context_EndRequest);
            }
        }                     

        #endregion
    }
}
